﻿using CommandSystem;
using Exiled.API.Features;
using Exiled.Events.EventArgs.Server;
using MEC;
using PlayerRoles;
using RemoteAdmin;
using RgCore.Commands;
using RgCore.Modules;
using RgCore.PlayerHud;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace ScpSwap
{
    public class ScpSwapCommand : ICommand
    {
        public string Command => "scp";

        public string[] Aliases => Array.Empty<string>();

        public string Description => "申请与另一个玩家交换SCP身份";

        public bool Execute(ArraySegment<string> arguments, ICommandSender sender, out string response)
        {
            Player player = Player.Get(sender);

            if (!player.IsScp)
            {
                response = "你不是SCP，想啥呢？";
                return false;
            }

            if (!ScpSwap.EventHandlers.AllowSwap)
            {
                response = "目前禁止互换角色";
                return false;
            }

            if (arguments.Count < 1)
            {
                response = "用法：.scp [SCP号码]";
                return false;
            }

            if (ScpSwap.EventHandlers.NameToRoleType.TryGetValue(arguments.ElementAt(0), out RoleTypeId RoleTypeId))
            {
                if (player.Role.Type == RoleTypeId)
                {
                    response = "不能和与你自己相同的角色互换";
                    return false;
                }

                Player target = Player.List.FirstOrDefault(x => x.Role == RoleTypeId);
                if (target != null)
                {
                    ScpSwap.EventHandlers.ReqCoroutines.Add(player, Timing.RunCoroutine(ScpSwap.EventHandlers.SendRequest(player, target)));
                    response = "互换请求已发送！";
                    return true;
                }
            }

            response = "没找到可以互换的玩家";
            return false;
        }
    }

    public class ScpSwapPlugin : RgPlugin
    {
        public override string Name => "SCP替补/互换功能";

        public override string Id => "scp_swap";

        public override void OnDisabled()
        {
            base.OnDisabled();
            EventHandlers.SetEnabled(false);
            ScpReplacement.RegisterEvents(false);
            QueryProcessor.DotCommandHandler.UnregisterCommand(QueryProcessor.DotCommandHandler.AllCommands.FirstOrDefault(x => x is ScpSwapCommand));
            QueryProcessor.DotCommandHandler.UnregisterCommand(QueryProcessor.DotCommandHandler.AllCommands.FirstOrDefault(x => x is ScpReplacementCommand));
        }

        public override void OnEnabled()
        {
            base.OnEnabled();
            EventHandlers.SetEnabled(true);
            ScpReplacement.RegisterEvents(true);
            QueryProcessor.DotCommandHandler.RegisterCommand(new ScpReplacementCommand());
            QueryProcessor.DotCommandHandler.RegisterCommand(new ScpSwapCommand());
        }
    }

    public static class EventHandlers
    {
        public static void SetEnabled(bool b)
        {
            if (b)
            {
                RgCore.RgCore.RoundStarted += OnRoundStart;
                Exiled.Events.Handlers.Server.RoundEnded += OnRoundEnd;
                DecisionCommand.PlayerAgree += DecisionCommand_PlayerAgree;
                DecisionCommand.PlayerRefuse += DecisionCommand_PlayerRefuse;
            }
            else
            {
                RgCore.RgCore.RoundStarted -= OnRoundStart;
                Exiled.Events.Handlers.Server.RoundEnded -= OnRoundEnd;
                DecisionCommand.PlayerAgree -= DecisionCommand_PlayerAgree;
                DecisionCommand.PlayerRefuse -= DecisionCommand_PlayerRefuse;
            }
        }

        private static void DecisionCommand_PlayerRefuse(Player player)
        {
            Player swap = ScpSwap.EventHandlers.OngoingReqs.FirstOrDefault(x => x.Value == player).Key;
            if (swap != null)
            {
                swap.SendFormattedMsg("refused", "<color=#FF0000>互换失败</color>", "你的互换请求已被拒绝", 5, MsgType.Failed_Response, ScreenLocation.CenterTop, true);
                Timing.KillCoroutines(ScpSwap.EventHandlers.ReqCoroutines[swap]);
                ScpSwap.EventHandlers.ReqCoroutines.Remove(swap);
                ScpSwap.EventHandlers.OngoingReqs.Remove(swap);
            }
        }

        private static void DecisionCommand_PlayerAgree(Player player)
        {
            Player swap = ScpSwap.EventHandlers.OngoingReqs.FirstOrDefault(x => x.Value == player).Key;
            if (swap != null)
            {
                ScpSwap.EventHandlers.PerformSwap(swap, player);
                ServerLogs.AddLog(ServerLogs.Modules.ClassChange, "[SCP互换]" + "互换的SCP玩家1: " + $"{swap.Role.Name} " + "互换的SCP玩家2: " + $"{player.Role.Name}", ServerLogs.ServerLogType.GameEvent);
                Timing.KillCoroutines(ScpSwap.EventHandlers.ReqCoroutines[swap]);
                ScpSwap.EventHandlers.ReqCoroutines.Remove(swap);
            }
        }

        public static Dictionary<Player, Player> OngoingReqs = new Dictionary<Player, Player>();

        public static List<CoroutineHandle> Coroutines = new List<CoroutineHandle>();

        public static Dictionary<Player, CoroutineHandle> ReqCoroutines = new Dictionary<Player, CoroutineHandle>();

        public static Dictionary<string, RoleTypeId> NameToRoleType = new Dictionary<string, RoleTypeId>()
        {
            { "173", RoleTypeId.Scp173 },
            { "939", RoleTypeId.Scp939 },
            { "079", RoleTypeId.Scp079 },
            { "79", RoleTypeId.Scp079 },
            { "106", RoleTypeId.Scp106 },
            { "096", RoleTypeId.Scp096 },
            { "96", RoleTypeId.Scp096 },
            { "049", RoleTypeId.Scp049 },
            { "49", RoleTypeId.Scp049 },
            { "0492", RoleTypeId.Scp0492 },
            { "492", RoleTypeId.Scp0492 },
        };

        public static bool AllowSwap = false;

        private const uint swapRequestTimeout = 30;

        public static IEnumerator<float> SendRequest(Player source, Player dest)
        {
            OngoingReqs.Add(source, dest);
            dest.SendFormattedMsg("swap", "<color=#FF2222>SCP互换请求</color>", $"请求者：<color=#FF0000>{source.Role.Type}</color>，<color=red>.v ty</color>(<color=red>F9</color>)接受 | <color=red>.v fd</color>(<color=red>F10</color>)反对", swapRequestTimeout, MsgType.Message, ScreenLocation.CenterTop, false);
            yield return Timing.WaitForSeconds(swapRequestTimeout);
            TimeoutRequest(source);
        }

        public static void TimeoutRequest(Player source)
        {
            if (OngoingReqs.ContainsKey(source))
            {
                source.SendFormattedMsg("failed", "<color=#FF0000>互换超时</color>", "你指定的玩家并没有回复你的请求", 5, MsgType.Failed_Response, ScreenLocation.CenterTop, true);
                OngoingReqs.Remove(source);
            }
        }

        public static void PerformSwap(Player source, Player dest)
        {
            RoleTypeId sRole = source.Role.Type;
            RoleTypeId dRole = dest.Role.Type;
            Vector3 sPos = source.Position;
            Vector3 dPos = dest.Position;
            float sHealth = source.Health;
            float dHealth = dest.Health;
            source.Role.Set(dRole);
            source.Position = dPos;
            source.Health = dHealth;
            dest.Role.Set(sRole);
            dest.Position = sPos;
            dest.Health = sHealth;
            OngoingReqs.Remove(source);
        }

        public static void OnRoundStart()
        {
            AllowSwap = true;
            Timing.CallDelayed(60f, () => AllowSwap = false);
        }

        public static void OnRoundEnd(RoundEndedEventArgs ev)
        {
            foreach (CoroutineHandle hndl in Coroutines)
                Timing.KillCoroutines(hndl);
            foreach (CoroutineHandle hndl in ReqCoroutines.Values)
                Timing.KillCoroutines(hndl);
            Coroutines.Clear();
            ReqCoroutines.Clear();
        }
    }
}